﻿/*!
pnView, a "page number view" generator module.
Created By NanaLich. 2010-09-07
This module is published under WTFPL v2, so you just DO WHAT THE Fxxx YOU WANT TO with it.
*/
!function () {
  var g = this;

  var def_maxSiblings = 2;
  var def_preventFolding = 1;

  function pnView1(
    currentPage, actionPageNum, actionFolding,
    maxSiblings, preventFolding
  ) {
    /// <summary>
    /// 使用传入的委托计算并产生友好的页码。
    /// </summary>
    /// <param name="currentPage">当前页码</param>
    /// <param name="actionPageNum">处理页码的方式</param>
    /// <param name="actionFolding">处理被折叠页码的方式</param>
    /// <param name="maxSiblings">临近页码的数量</param>
    /// <param name="preventFolding">阻止折叠页码的临界值，超过这个数目的页码将会被折叠</param>

    pnView2(currentPage, actionPageNum, actionPageNum, actionFolding, maxSiblings || def_maxSiblings, preventFolding || def_preventFolding);
  }

  function pnView2(
    currentPage, actionCurrent,
    actionPageNum, actionFolding,
    maxSiblings, preventFolding
  ) {
    /// <summary>
    /// 使用传入的委托计算并产生友好的页码。当前页码将会被特别对待。
    /// </summary>
    /// <param name="currentPage">当前页码</param>
    /// <param name="actionCurrent">处理当前页码的方式</param>
    /// <param name="actionPageNum">处理页码的方式</param>
    /// <param name="actionFolding">处理被折叠页码的方式</param>
    /// <param name="maxSiblings">临近页码的数量</param>
    /// <param name="preventFolding">阻止折叠页码的临界值，超过这个数目的页码将会被折叠</param>

    pnView(
      currentPage, actionCurrent,
      1, Number.POSITIVE_INFINITY,
      actionPageNum, null,
      maxSiblings || def_maxSiblings, actionPageNum,
      preventFolding || def_preventFolding, actionFolding,
      maxSiblings || def_maxSiblings, 0,
      actionPageNum, null
    );
  }

  function pnView3(
    currentPage, actionCurrent,
    beginPage, endPage,
    actionPageNum, actionFolding,
    maxSiblings, preventFolding
  ) {
    /// <summary>
    /// 根据传入的参数和委托来计算并产生友好的页码。当前页码将会被特别对待。
    /// </summary>
    /// <param name="currentPage">当前页码</param>
    /// <param name="actionCurrent">处理当前页码的方式</param>
    /// <param name="beginPage">预设的起始页码</param>
    /// <param name="endPage">预设的结束页码</param>
    /// <param name="actionPageNum">处理页码的方式</param>
    /// <param name="actionFolding">处理被折叠页码的方式</param>
    /// <param name="maxSiblings">临近页码的数量</param>
    /// <param name="preventFolding">阻止折叠页码的临界值，超过这个数目的页码将会被折叠</param>

    pnView4(currentPage, actionCurrent, beginPage, endPage, actionPageNum, actionPageNum, actionPageNum, actionFolding, maxSiblings || def_maxSiblings, preventFolding || def_preventFolding);
  }

  function pnView4(
    currentPage, actionCurrent,
    beginPage, endPage,
    actionBegin, actionEnd,
    actionSebling, actionFolding,
    maxSiblings, preventFolding
  ) {
    /// <summary>
    /// 根据传入的参数和委托来计算并产生友好的页码。当前页码、起始页码和终止页码都指定了专用的委托来处理。
    /// </summary>
    /// <param name="currentPage">当前页码</param>
    /// <param name="actionCurrent">处理当前页码的方式</param>
    /// <param name="beginPage">预设的起始页码</param>
    /// <param name="endPage">预设的结束页码</param>
    /// <param name="actionBegin">处理起始页码的方式</param>
    /// <param name="actionEnd">处理结束页码的方式</param>
    /// <param name="actionSebling">处理临近页码的方式</param>
    /// <param name="actionFolding">处理被折叠页码的方式</param>
    /// <param name="maxSiblings">临近页码的数量</param>
    /// <param name="preventFolding">阻止折叠页码的临界值，超过这个数目的页码将会被折叠</param>

    pnView(
      currentPage, actionCurrent,
      beginPage, endPage,
      actionBegin, actionEnd,
      maxSiblings || def_maxSiblings, actionSebling,
      preventFolding || def_preventFolding, actionFolding,
      maxSiblings || def_maxSiblings, maxSiblings || def_maxSiblings,
      actionSebling, actionSebling
    );
  }

  function pnView(
    currentPage, actionCurrent,
    beginPage, endPage,
    actionBegin, actionEnd,
    currentSiblings, actionCurrentSibling,
    preventFolding, actionFolding,
    endOfBegin, beginOfEnd,
    actionBeginSibling, actionEndSibling
  ) {
    /// <summary>
    /// 根据传入的参数和委托来计算并产生友好的页码。每一种页码的具体处理方式都需要由调用方指派委托。
    /// </summary>
    /// <param name="currentPage">当前页码</param>
    /// <param name="actionCurrent">处理当前页码的方式</param>
    /// <param name="beginPage">预设的起始页码</param>
    /// <param name="endPage">预设的结束页码</param>
    /// <param name="actionBegin">处理起始页码的方式</param>
    /// <param name="actionEnd">处理结束页码的方式</param>
    /// <param name="currentSiblings">当前页码的临近页码数量</param>
    /// <param name="actionCurrentSibling">处理临近页码的方式</param>
    /// <param name="preventFolding">阻止折叠页码的临界值，超过这个数目的页码将会被折叠</param>
    /// <param name="actionFolding">处理被折叠页码的方式</param>
    /// <param name="endOfBegin">起始页临近页码的数量</param>
    /// <param name="beginOfEnd">结束页临近页码的数量</param>
    /// <param name="actionBeginSibling">处理起始页临近页码的方式</param>
    /// <param name="actionEndSibling">处理结束页临近页码的方式</param>

    var i = beginPage;

    // 如果起始页小于当前页，就开始处理起始页
    if (beginPage < currentPage) {
      actionBegin && actionBegin(beginPage);
      i++;

      endOfBegin += i; // 解决靠近起始页的页码之后
      var siblingBegin = currentPage - currentSiblings; // 当前页的临近页从何处开始
      var foldingStart = siblingBegin - preventFolding; // 页码折叠的底线

      if (endOfBegin > siblingBegin)
        endOfBegin = siblingBegin; // 保证当前页的临近页，牺牲起始页的临近页

      for (; i < endOfBegin; i++)
        actionBeginSibling && actionBeginSibling(i);

      if (i < foldingStart) // 如果还没到达折叠底线，就马上开始折叠
      {
        actionFolding && actionFolding();
        i = foldingStart + 1; // 跳到折叠之后的页码
      }
    }

    // 处理当前页之前的临近页
    for (; i < currentPage; i++)
      actionCurrentSibling && actionCurrentSibling(i);

    // 处理当前页
    actionCurrent && actionCurrent(currentPage);
    i = currentPage + 1; // 表示当前页已经处理完成。
    // 由于不能保证当前页和期望的起始页的关系，所以在此从当前页开始计算。

    var goal = i + currentSiblings; // 设定一个目标
    if (goal > endPage) // 目标不要超过结束页
      goal = endPage;

    // 处理当前页之后的临近页，直到到达目标页为止
    for (; i < goal; i++)
      actionCurrentSibling && actionCurrentSibling(i);

    // 如果结束页大于当前页，就开始处理结束页
    if (endPage > currentPage) {
      beginOfEnd = endPage - beginOfEnd; // 计算出结束页的临近页从何处开始
      var foldingStart = beginOfEnd - preventFolding;

      if (i < foldingStart) // 没有触及折叠底线，马上开始折叠
      {
        actionFolding && actionFolding();

        i = beginOfEnd;
      }
      else // 全部当作当前页的临近页来处理，但保留结束页的临近页
      {
        for (; i < beginOfEnd; i++)
          actionCurrentSibling && actionCurrentSibling(i);
      }


      for (; i < endPage; i++)
        actionEndSibling && actionEndSibling(i);
      actionEnd && actionEnd(endPage);
    }

  }

  g.pnView1 = pnView1;
  g.pnView2 = pnView2;
  g.pnView3 = pnView3;
  g.pnView4 = pnView4;
  g.pnView5 = pnView;
  g.pnView = pnView;

} ();

